﻿//SecurityChange.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Storages
{
	using System;

	using Ecng.Common;
	using Ecng.ComponentModel;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Типы значения изменения в <see cref="SecurityChange"/>, которое записано в <see cref="SecurityChange.Value"/>.
	/// </summary>
	[Flags]
	public enum SecurityChangeTypes
	{
		/// <summary>
		/// <see cref="Security.OpenPrice"/>.
		/// </summary>
		[EnumDisplayName("Цена открытия")]
		OpenPrice = 1,

		/// <summary>
		/// <see cref="Security.HighPrice"/>.
		/// </summary>
		[EnumDisplayName("Наибольшая цены")]
		HighPrice = OpenPrice << 1,

		/// <summary>
		/// <see cref="Security.LowPrice"/>.
		/// </summary>
		[EnumDisplayName("Наименьшая цена")]
		LowPrice = HighPrice << 1,

		/// <summary>
		/// <see cref="Security.ClosePrice"/>.
		/// </summary>
		[EnumDisplayName("Цена закрытия")]
		ClosePrice = LowPrice << 1,

		/// <summary>
		/// <see cref="Security.LastTrade"/>.
		/// </summary>
		[EnumDisplayName("Последняя сделка")]
		LastTrade = ClosePrice << 1,

		/// <summary>
		/// <see cref="Security.MinStepPrice"/>.
		/// </summary>
		[EnumDisplayName("Стоимость шага")]
		MinStepPrice = LastTrade << 1,

		/// <summary>
		/// <see cref="Security.BestBid"/>.
		/// </summary>
		[EnumDisplayName("Лучший бид")]
		BestBid = MinStepPrice << 1,

		/// <summary>
		/// <see cref="Security.BestAsk"/>.
		/// </summary>
		[EnumDisplayName("Лучший оффер")]
		BestAsk = BestBid << 1,

		/// <summary>
		/// <see cref="Security.ImpliedVolatility"/>.
		/// </summary>
		[EnumDisplayName("Волатильность (подразумеваемая)")]
		ImpliedVolatility = BestAsk << 1,

		/// <summary>
		/// <see cref="Security.TheorPrice"/>.
		/// </summary>
		[EnumDisplayName("Теор цена")]
		TheorPrice = ImpliedVolatility << 1,

		/// <summary>
		/// <see cref="Security.OpenInterest"/>.
		/// </summary>
		[EnumDisplayName("Открытый интерес")]
		OpenInterest = TheorPrice << 1,

		/// <summary>
		/// <see cref="Security.MinPrice"/>.
		/// </summary>
		[EnumDisplayName("Минимальная цена")]
		MinPrice = OpenInterest << 1,

		/// <summary>
		/// <see cref="Security.MaxPrice"/>.
		/// </summary>
		[EnumDisplayName("Максимальная цена")]
		MaxPrice = MinPrice << 1,

		/// <summary>
		/// <see cref="Security.BidsVolume"/>.
		/// </summary>
		[EnumDisplayName("Объем бидов")]
		BidsVolume = MaxPrice << 1,

		/// <summary>
		/// <see cref="Security.BidsCount"/>.
		/// </summary>
		[EnumDisplayName("Кол-во бидов")]
		BidsCount = BidsVolume << 1,

		/// <summary>
		/// <see cref="Security.AsksVolume"/>.
		/// </summary>
		[EnumDisplayName("Объем офферов")]
		AsksVolume = BidsCount << 1,

		/// <summary>
		/// <see cref="Security.AsksCount"/>.
		/// </summary>
		[EnumDisplayName("Кол-во офферов")]
		AsksCount = AsksVolume << 1,

		/// <summary>
		/// <see cref="Security.HistoricalVolatility"/>.
		/// </summary>
		[EnumDisplayName("Волатильность (историческая)")]
		HistoricalVolatility = AsksCount << 1,

		/// <summary>
		/// <see cref="Security.Delta"/>.
		/// </summary>
		[EnumDisplayName("Дельта")]
		Delta = HistoricalVolatility << 1,

		/// <summary>
		/// <see cref="Security.Gamma"/>.
		/// </summary>
		[EnumDisplayName("Гамма")]
		Gamma = Delta << 1,

		/// <summary>
		/// <see cref="Security.Vega"/>.
		/// </summary>
		[EnumDisplayName("Вега")]
		Vega = Gamma << 1,

		/// <summary>
		/// <see cref="Security.Theta"/>.
		/// </summary>
		[EnumDisplayName("Тета")]
		Theta = Vega << 1,

		/// <summary>
		/// <see cref="Security.MarginBuy"/>.
		/// </summary>
		[EnumDisplayName("ГО (покупка)")]
		MarginBuy = Theta << 1,

		/// <summary>
		/// <see cref="Security.MarginSell"/>.
		/// </summary>
		[EnumDisplayName("ГО (продажа)")]
		MarginSell = MarginBuy << 1,

		/// <summary>
		/// <see cref="Security.MinStepSize"/>.
		/// </summary>
		[EnumDisplayName("Минимальный шаг цены")]
		MinStepSize = MarginSell << 1,
	}

	/// <summary>
	/// Изменение инструмента, хранящее в себе признак того, что изменилось.
	/// </summary>
	public class SecurityChange : Equatable<SecurityChange>
	{
		/// <summary>
		/// Создать <see cref="SecurityChange"/>.
		/// </summary>
		/// <param name="security">Инструмент.</param>
		/// <param name="time">Время изменения.</param>
		/// <param name="type">Тип значения, которое записано в <see cref="Value"/>.</param>
		/// <param name="value">Одно из частей инструмента.</param>
		public SecurityChange(Security security, DateTime time, SecurityChangeTypes type, object value)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			if (value == null)
				throw new ArgumentNullException("value");

			Security = security;
			Time = time;
			Type = type;
			Value = value;
		}

		/// <summary>
		/// Инструмент.
		/// </summary>
		public Security Security { get; private set; }

		/// <summary>
		/// Тип значения, которое записано в <see cref="Value"/>.
		/// </summary>
		public SecurityChangeTypes Type { get; private set; }

		/// <summary>
		/// Время изменения.
		/// </summary>
		public DateTime Time { get; set; }

		/// <summary>
		/// Одно из частей инструмента.
		/// </summary>
		public object Value { get; private set; }

		/// <summary>
		/// Создать копию изменения.
		/// </summary>
		/// <returns>Копия изменения.</returns>
		public override SecurityChange Clone()
		{
			return new SecurityChange(Security, Time, Type, Value);
		}

		/// <summary>
		/// Сравнить изменение на эквивалентность.
		/// </summary>
		/// <param name="other">Другое изменение для сравнения.</param>
		/// <returns>True, если изменения эквивалентны, иначе, false.</returns>
		protected override bool OnEquals(SecurityChange other)
		{
			if (Security == other.Security && Type == other.Type && Time == other.Time)
			{
				if (Type == SecurityChangeTypes.LastTrade)
				{
					var t1 = (Trade)Value;
					var t2 = (Trade)other.Value;

					return t1.Price == t2.Price && t1.Volume == t2.Volume && t1.OrderDirection == t2.OrderDirection;
				}
				else
					return Value.Equals(other.Value);
			}

			return false;
		}

		/// <summary>
		/// Рассчитать хеш-код объекта <see cref="SecurityChange"/>.
		/// </summary>
		/// <returns>Хеш-код.</returns>
		public override int GetHashCode()
		{
			return Security.GetHashCode() ^ Type.GetHashCode() ^ Time.GetHashCode() ^ Value.GetHashCode();
		}

		/// <summary>
		/// Получить строковое представление.
		/// </summary>
		/// <returns>Строковое представление.</returns>
		public override string ToString()
		{
			return "{0} {1} {2}".Put(Time, Type, Value);
		}
	}
}